package com.blue.integration.spring.resource;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.util.Assert;

/**
 * Simple implementation of {@link org.springframework.context.MessageSource}
 * which allows messages to be registered programmatically.
 * This MessageSource supports basic internationalization.
 *
 * <p>Intended for testing rather than for use in production systems.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
public class StaticMessageSource extends AbstractMessageSource
{
	private static Logger logger = LoggerFactory.getLogger(StaticMessageSource.class);

	/** Map from 'code + locale' keys to message Strings */
	private Map<String, String> messages = new HashMap<String, String>();

	private Map<String, MessageFormat> cachedMessageFormats = new HashMap<String, MessageFormat>();


	@Override
	protected String resolveCodeWithoutArguments(String code, Locale locale)
	{
		String msg = messages.get(this.getKey(code, locale));
		if (msg != null && !msg.isEmpty())
			return msg;
		
		msg = messages.get(this.getLanguageKey(code, locale));
		if (msg != null && !msg.isEmpty())
			return msg;
		
		return messages.get(code);
	}

	@Override
	protected MessageFormat resolveCode(String code, Locale locale)
	{
		String msg = this.resolveCodeWithoutArguments(code, locale);
		if (msg == null)
			return null;
		
		String key = code + "_" + locale.toString();
		synchronized (cachedMessageFormats)
		{
			MessageFormat messageFormat = cachedMessageFormats.get(key);
			
			if (messageFormat == null)
			{
				messageFormat = this.createMessageFormat(msg, locale);
				cachedMessageFormats.put(key, messageFormat);
			}
			return messageFormat;
		}
	}

	/**
	 * Associate the given message with the given code.
	 * @param code the lookup code
	 * @param locale the locale that the message should be found within
	 * @param msg the message associated with this lookup code
	 */
	public void addMessage(String code, Locale locale, String msg) {
		Assert.notNull(code, "Code must not be null");
		Assert.notNull(locale, "Locale must not be null");
		Assert.notNull(msg, "Message must not be null");
		this.messages.put(code + "_" + locale.toString(), msg);
		if (logger.isDebugEnabled()) {
			logger.debug("Added message [" + msg + "] for code [" + code + "] and Locale [" + locale + "]");
		}
	}

	/**
	 * Associate the given message values with the given keys as codes.
	 * @param messages the messages to register, with messages codes
	 * as keys and message texts as values
	 * @param locale the locale that the messages should be found within
	 */
	public void addMessages(Map<String, String> messages, Locale locale) {
		Assert.notNull(messages, "Messages Map must not be null");
		for (Map.Entry<String, String> entry : messages.entrySet()) {
			addMessage(entry.getKey(), locale, entry.getValue());
		}
	}
	
	public void addMessage(String key, String value)
	{
		Assert.notNull(key, "Key must not be null");
		Assert.notNull(value, "Value must not be null");
		messages.put(key, value);
		if (logger.isDebugEnabled())
		{
			logger.debug("Added message [{}] for code [{}]", value, key);
		}
	}
	
	private String getLanguageKey(String code, Locale locale)
	{
		return code + "_" + locale.getLanguage();
	}
	
	private String getKey(String code, Locale locale)
	{
		return code + "_" + locale.toString();
	}
	
	/**
	 * 移除
	 * 
	 * @param code 代码
	 * @param locale 语言
	 */
	public void removeMessage(String code, Locale locale)
	{
		String key = code + "_" + locale.toString();
		this.messages.remove(key);
		this.cachedMessageFormats.remove(key);
	}
	
	/**
	 * 重新加载
	 * 
	 * @param message 资源
	 */
	public void reloadMessage(Map<String, String> messages)
	{
		this.messages = messages;
		if (cachedMessageFormats != null)
		{
			cachedMessageFormats.clear();
		}
	}


	@Override
	public String toString() {
		return getClass().getName() + ": " + this.messages;
	}

}
